﻿using System;
using System.Collections;
using System.Runtime.InteropServices;

namespace Eflong.Structure
{
    public interface IRecord
    {
        void ToByteArray( byte[ ] ba , ref int pos );

        byte[ ] GetBytes( );
    }

    [StructLayout( LayoutKind.Sequential )]//, Pack=1)]
    public struct Record : IRecord
    {
        private const int SIZE_MONUNITID = 9;

        public Record( string id , DateTime time , float value , byte state )
        {
            m_nYear = Convert.ToUInt16( time.Year );
            m_nMonth = Convert.ToByte( time.Month );
            m_nDay = Convert.ToByte( time.Day );
            m_nHour = Convert.ToByte( time.Hour );
            m_nMinute = Convert.ToByte( time.Minute );
            m_nSecond = Convert.ToByte( time.Second );
            m_szId = id;
            m_fValue = value;
            m_nState = state;
        }

        public UInt16 m_nYear;
        public byte m_nMonth;
        public byte m_nDay;
        public byte m_nHour;
        public byte m_nMinute;
        public byte m_nSecond;

        [MarshalAs( UnmanagedType.ByValTStr , SizeConst = SIZE_MONUNITID )]
        public string m_szId;

        public byte m_nState;
        public float m_fValue;

        public static Record OnPacket( byte[ ] packet )
        {
            GCHandle pinnedPacket = GCHandle.Alloc( packet , GCHandleType.Pinned );

            // IntPtr ptr = pinnedPacket.AddrOfPinnedObject();

            Record record = ( Record )Marshal.PtrToStructure(
                pinnedPacket.AddrOfPinnedObject( ) ,
                typeof( Record ) );
            pinnedPacket.Free( );
            return record;
        }

        /// <summary>
        /// 获取当前结构的字节数组
        /// </summary>
        /// <returns></returns>
        public byte[ ] GetBytes( )
        {
            byte[ ] ba = new byte[ Sizeof( ) ];
            IntPtr ptr = Marshal.UnsafeAddrOfPinnedArrayElement( ba , 0 );
            Marshal.StructureToPtr( this , ptr , true );
            return ba;
        }

        /// <summary>
        /// 把当前的结构转换到一个数组中
        /// </summary>
        /// <param name="ba"></param>
        /// <param name="pos"></param>
        public void ToByteArray( byte[ ] ba , ref int pos )
        {
            IntPtr ptr = Marshal.UnsafeAddrOfPinnedArrayElement( ba , pos );
            Marshal.StructureToPtr( this , ptr , true );
            pos += Sizeof( );
        }

        /// <summary>
        /// 从字节数组中获取一批结构数组
        /// </summary>
        /// <param name="packets">byte 数组</param>
        /// <returns></returns>
        public static ArrayList GetRecords( byte[ ] packets )
        {
            ArrayList list = new ArrayList( );
            GCHandle pinnedPacket = GCHandle.Alloc( packets , GCHandleType.Pinned );
            int size = Record.Sizeof( );// Marshal.SizeOf(record);
            int count = packets.Length / size;
            int n = 0;
            int pos = 0;
            while ( n < count )
            {
                //IntPtr ptr = pinnedPacket.AddrOfPinnedObject();

                Record p = ( Record )Marshal.PtrToStructure(
                                Marshal.UnsafeAddrOfPinnedArrayElement( packets , pos ) ,
                                typeof( Record ) );
                list.Add( p );
                n++;
                pos += size;
            }
            pinnedPacket.Free( );
            return list;
        }

        private static int size = 0;

        public static int Sizeof( )
        {
            if ( size == 0 )
            {
                Record record = new Record( );
                size = Marshal.SizeOf( record );
            }
            return size;
        }

        public override string ToString( )
        {
            return string.Format( "{0} , {1:f2}, {2}, {3}-{4}-{5} {6}:{7}:{8} " , m_szId , m_fValue , m_nState ,
                m_nYear , m_nMonth , m_nDay , m_nHour , m_nMinute , m_nSecond );
        }
    }
}